#!/usr/bin/env python
#Created May 9 2008 Pawel Gieniec v0.1
#This module will parse all of our HTML
#The basic design is as follows:
#Super class holds
#one string, the tag i.e. <p> or <body> or etc..
#one array to store all the argument tags i.e. align="center" etc..
#one array to store all the data

#Finished May 19 2008
#For my purposes this module contains all necessary html elements.
#If you need more, feel free to add them on.

#The global class, contains global vars
#Also contains general print, and add methods
class Super:
        
    #add to our data array
    def addData(self,in_sData):
        self.m_sData.append(in_sData)
    
    #add to our args array
    def addArgs(self, in_sArgs):
        self.m_sArgs.append(in_sArgs)
    
    #add to our tags string
    def addTags(self,in_sTags):
        self.m_sTags.append(in_sTags)
        
    #allow other elements to be embedded into our paragraph
    def addE(self,in_sElement):
        self.m_sData.append(str(in_sElement))
        
    #return the opening tag, with arguments i.e. < tag + args>
    def openTags(self):
        if (len(self.m_sArgs) > 0):
            return "<" + "".join(self.m_sTags) + " " + " ".join(self.m_sArgs) + ">"
        else:
            return "<" + "".join(self.m_sTags) + ">"

    #return the closing tag, < / tag >
    def closeTags(self):
        return "<" + "/" + "".join(self.m_sTags) + ">\n"
    
    #return < tag + args> data + < / tag>
    def __repr__(self):
        return self.openTags() + "".join(self.m_sData) + self.closeTags()
    
    #The global variables that hold the tag, args, and data
    def init(self):
        self.m_sTags     = []
        self.m_sArgs     = []
        self.m_sData     = []
        self.m_oElements = []

#This is the document class, which
class doc(Super):
    
    #some usually gibberish
    m_sDoctype = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">\n """
    m_sLHTML = """<!--Page Generated with the LameHTML Python Module <http://code.google.com/p/lhtml/>-->\n"""

    m_sCSS = ""
    #constructor initializes some tags
    def __init__(self,in_sName,in_sCSS=None):
        self.init()
        self.addTags("html")
        self.m_sTitle = "<title>" + in_sName + "</title>"
        self.addTags("body")
        if in_sCSS is not None:
            self.m_sCSS = """<LINK href=""" + "\"" + in_sCSS + "\"" """ rel="stylesheet" type="text/css">\n """
    
    #print out the entire document with all elements and arguments attached
    def __repr__(self):
        return self.m_sDoctype + self.m_sLHTML + self.m_sCSS + self.openTags() + self.m_sTitle + "\n" + "\n".join(self.m_sData) + self.closeTags()

    #return all the tags, html, head, title, body on new lines
    def openTags(self):
        sRes = ""
        for sTemp in self.m_sTags:
            sRes += "<" + sTemp + ">" + "\n"
        return sRes

    #return all the tags html body in reverse over on new lines
    def closeTags(self):
        if (self.m_sData.count == 0):
            sRes = "\n"
        else:
            sRes = ""
        self.m_sTags.reverse()
        for sTemp in self.m_sTags:
            sRes += "</" + sTemp + ">" + "\n"
        return sRes
    
#The paragraph class i.e. <p> Hello World! </p>
class p(Super):
    
    #constructor, the None is used for overloading purposes
    def __init__(self,in_sData,in_sArgs=None):
        self.init()
        if in_sArgs is not None:
            self.addArgs(in_sArgs)
        self.addTags("p")
        self.addData(in_sData)

#The emphasis class i.e. <em> moi! </em>        
class em(Super):
    
    #constructor, overloaded
    def __init__(self,in_sData,in_sArgs=None):
        self.init()
        if in_sArgs is not None:
            self.addArgs(in_sArgs)
        self.addTags("em")
        self.addData(in_sData)
        
#The Anchor class i.e. <a href="http://code.google.com/p/lhtml/"> LameHTML </a>
class a(Super):
    
    #constructor, overloaded
    def __init__(self,in_sName,in_sLink):
        self.init()
        self.addTags("a")
        self.addData(in_sName)
        sLink = "href=" + "\"" + in_sLink + "\""
        self.addArgs(sLink)
    
    def __repr__(self):
        return self.openTags() + "".join(self.m_sData) + self.closeTags()

#still deciding whether headings should be combined into one class or made all sepearte
#to simplify module syntax
class head(Super):
    
    def __init__(self,in_nNum,in_sData=None,in_sArgs=None):
        self.init()
        if in_sArgs is not None:
            self.addArgs(in_sArgs)
        if in_sData is not None:
            self.addData(in_sData)
        self.addTags("h"+str(in_nNum))
    
#the form class, nuff said
class form(Super):
    
    #constructor
    def __init__(self,in_sData=None,in_sArgs=None):
        self.init()
        if in_sArgs is not None:
            self.addArgs(in_sArgs)
        if in_sData is not None:
            self.addData(in_sData)
        self.addTags("form")

#input class that will allow the user to create
#any html input type and include it into the form
class input(Super):
    
    #constructor
    def __init__(self,in_sLabel,in_sArgs):
        self.init()
        self.m_sLabel = in_sLabel
        self.addArgs(in_sArgs)
    
    def __repr__(self):
        return self.m_sLabel + "\n<input "+ " ".join(self.m_sArgs) + " />"

#the div class
class div(Super):
    
    #constructor
    def __init__(self,in_sArgs,in_sData=None):
        self.init()
        if in_sData is not None:
            self.addData(in_sData)
        self.addTags("div")
        self.addArgs(in_sArgs)

#the img class
class img(Super):
        
    #constructor
    def __init__(self,in_sLink,in_sArgs=None):
        self.init()
        sLink = "src=" + "\"" + in_sLink + "\""
        self.addArgs(sLink)
        if in_sArgs is not None:
            self.addArgs(in_sArgs)
        self.addTags("img")

    #we don't need to close the img tag
    def __repr__(self):
        return "<" + self.m_sTags[0] + " " + " ".join(self.m_sArgs) + " />"

#The selection class i.e. <select> <option> Hello World! </option> </select>
class selection(Super):

    #constructor
    def __init__(self,in_sArgs=None):
        self.init()
        self.m_sValue = {}
        if in_sArgs is not None:
            self.addArgs(in_sArgs)
        self.addTags("select")
        
    #add options, where we can specify the value tag in each option tag
    def addData(self,in_sData,in_sValue=None):
        if in_sValue is not None:
            self.m_sValue[in_sData] = in_sValue
        self.m_sData.append(in_sData)
        
    #print out our select html element properly
    def __repr__(self):
        if (len(self.m_sArgs) > 0):
            return "<" + self.m_sTags[0] + " " + " ".join(self.m_sArgs) + ">\n" + self.printInternal() + "</select>"
        else:
            return "<" + self.m_sTags[0] +">\n" + self.printInternal() + "</select>"
    
    #print out the <option> tags
    def printInternal(self):
        sTemp = ""
        for x in self.m_sData:
            sTemp += self.openTags("option",x) + x + self.closeTags("option") + "\n"
        return sTemp
        
    # return a open html tag <in_sTag>
    def openTags(self,in_sTag,in_sData):
        return "<" + "".join(in_sTag) + " " + self.m_sValue[in_sData] + ">"
    
    # return a close html tag </in_sTag>
    def closeTags(self,in_sTag):
        return "</" + "".join(in_sTag) + ">"
    
#The table class i.e. <table> <tr> <td> Hello World! </td> </tr> </table>
class table(Super):
    
    #constructor
    def __init__(self,in_nRows,in_nCols,in_sArgs=None):
        self.init(in_nRows,in_nCols)
        self.addTags("table")
        self.addTags("tr")
        self.addTags("th")
        self.addTags("td")
        if in_sArgs is not None:
            self.addArgs(in_sArgs)
        print self.m_sCols
    
    #adds headers to this table <TH>
    def addHeadArgs(self,in_sArgs):
        self.m_sHeadArgs.append(in_sArgs)
    
    #add data within the tables head tags
    #can pass in a simple string, or even one of our objects
    def addHeadData(self,in_sData):
        self.m_sHeadData.append(str(in_sData))
    
    #create two dimensional list to represent our table
    #create two lists, one for the row headings, and col headings
    def init(self,in_nRows,in_nCols):
        self.m_sTags = []
        self.m_sArgs = []
        self.m_sHeadArgs = []
        self.m_sHeadData = []
        self.m_sCols = []
        self.m_nMaxCol = in_nCols
        for x in range(0,in_nRows):
            self.m_sRow = []
            for y in range(0,in_nCols):
                self.m_sRow.append('')
            self.m_sCols.append(self.m_sRow)    
        self.m_sHCols = []
    
    #ok lets create our html syntax    
    def __repr__(self):
        return self.openTags(self.m_sTags[0],1) + self.openTags(self.m_sTags[2],2) + "\n".join(self.m_sHeadData) + self.closeTags(self.m_sTags[2]) + self.getData() + self.closeTags(self.m_sTags[0])
    
    #return all the data in our table in proper html format
    def getData(self):
        sResult = ""
        for x in self.m_sCols:
            sResult += self.openTags(self.m_sTags[1],0)
            for y in x:
                sResult += "\t" + self.openTags(self.m_sTags[3],0)
                sResult += str(y)
                sResult += "\t" + self.closeTags(self.m_sTags[3])
                pass
        sResult += self.closeTags(self.m_sTags[1])
        return sResult
    
    #returns the number of cols in our table
    #useful for for loops while filling in the table
    def getNumCols(self):
        return self.m_nMaxCol
    
    #put tags around the input string
    def openTags(self,in_sTag,in_nC):
        if in_nC == 0:
            return "<" + in_sTag + ">\n"    
        elif in_nC == 1:
            return "<" + in_sTag + " ".join(self.m_sArgs) + ">\n"
        elif in_nC == 2:
            return "<" + in_sTag + " ".join(self.m_sHeadArgs) + ">\n"
    
    #put tags and a slash around the input string
    def closeTags(self,in_sTag):
        return "</" + in_sTag + ">\n"
    
    #overload the default mapping to
    #allow us to map the 2d array within
    #each table to the table instance
    #assuming we have a competent user ;)
    #i.e. t = table(3,4) then t[x,y] would be equivalent to self.m_sCols[x][y]
    def __setitem__(self,in_sCoor,in_sData):        
        nX = in_sCoor[0]
        #two dimensional
        if len(in_sCoor) > 1:            
            nY = in_sCoor[1]
            self.m_sCols[nX][nY] = str(in_sData)
        #one dimensional
        else:
            self.m_sCols[nX] = str(in_sData)